package administracion.managedBean.reservas;

import Entities.Cliente;
import Entities.Mesa;
import Entities.Reserva;
import ejb.ClienteFacadeLocal;
import ejb.Condicional;
import ejb.ConsultaUniversalFacadeLocal;
import ejb.MesaFacadeLocal;
import ejb.ReservaFacadeLocal;
import ejb.soportes.Consulta;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;
import org.primefaces.context.RequestContext;
import org.primefaces.model.LazyDataModel;
import sesion.PermisoPagina;
import tablemodel.GeneralLazyModel;
import util.PageCodeGenerico;

@ManagedBean
@ViewScoped
public class PCReserva extends PageCodeGenerico implements Serializable {

    @EJB
    private ReservaFacadeLocal entidadFacade;
    @EJB
    private ClienteFacadeLocal clienteFacade;
    @EJB
    private MesaFacadeLocal mesaFacade;
    @EJB
    private ConsultaUniversalFacadeLocal consultaUniversalFacade;
    private LazyDataModel<Reserva> listado;
    private Reserva temporal;
    private Properties colsVisible;
    private Map<String, String> checksVisible;
    private List<String> selectedChecksVisible;
    private Accion accion = Accion.CREAR;
    private Map<String, String> horarios;
    private Date fecha;
    private String nomUsuarioCheck;
    private String nombreUsuario;
    private List<Mesa> mesasSeleccionadas;
    private List<Mesa> listaMesas;
    private String fechaActual;
    private Map<String, Integer> mesas;
    private List<Object> selectedMesas;

    public PCReserva() {
        super();
        this.listado = new GeneralLazyModel<>(new Reserva());
        this.temporal = new Reserva();
        this.colsVisible = new Properties();
        this.fecha = new Date();
        this.cargarHorarios();
        Calendar cal = Calendar.getInstance();
        fechaActual = cal.get(Calendar.DATE) + "/" + (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.YEAR);
    }

    public void establecerHorarios() {
        Calendar cal = Calendar.getInstance();
        int dia = cal.get(Calendar.DAY_OF_MONTH);
        Calendar calDate = Calendar.getInstance();
        calDate.setTime(this.fecha);
        int diaIn = calDate.get(Calendar.DAY_OF_MONTH);
        if (dia != diaIn) {
            this.cargarHorarios();
        } else {
            horarios = new LinkedHashMap<String, String>();
            int hora = cal.get(Calendar.HOUR_OF_DAY);
            if (hora < 12) {
                horarios.put("1", "Mañana");
            }
            if (hora < 14) {
                horarios.put("2", "Medio día");
            }
            if (hora < 19) {
                horarios.put("3", "Tarde");
            }
            if (hora <= 24) {
                horarios.put("4", "Noche");
            }
        }
    }

    private void cargarHorarios() {
        horarios = new LinkedHashMap<String, String>();
        horarios.put("1", "Mañana");
        horarios.put("2", "Medio día");
        horarios.put("3", "Tarde");
        horarios.put("4", "Noche");
    }

    public SelectItem[] getSelectHorarios() {
        SelectItem[] selectHorarios;
        selectHorarios = new SelectItem[5];
        selectHorarios[0] = new SelectItem("", "TODOS");
        selectHorarios[1] = new SelectItem(1, "Mañana");
        selectHorarios[2] = new SelectItem(2, "Medio día");
        selectHorarios[3] = new SelectItem(3, "Tarde");
        selectHorarios[4] = new SelectItem(4, "Noche");
        return selectHorarios;
    }

    public String devolverHorario(int id) {
        return this.horarios.get(String.valueOf(id));
    }

    public Map<String, String> getHorarios() {
        this.establecerHorarios();
        return horarios;
    }

    public void setHorarios(Map<String, String> horarios) {
        this.horarios = horarios;
    }

    public String getNombreUsuario() {
        return nombreUsuario;
    }

    public void setNombreUsuario(String nombreUsuario) {
        this.nombreUsuario = nombreUsuario;
    }

    public Date getFecha() {
        return fecha;
    }

    public void setFecha(Date fecha) {
        this.fecha = fecha;
    }

    public String getNomUsuarioCheck() {
        return nomUsuarioCheck;
    }

    public void setNomUsuarioCheck(String nomUsuarioCheck) {
        this.nomUsuarioCheck = nomUsuarioCheck;
    }

    public List<Mesa> getMesasSeleccionadas() {
        return mesasSeleccionadas;
    }

    public void setMesasSeleccionadas(List<Mesa> mesasSeleccionadas) {
        this.mesasSeleccionadas = mesasSeleccionadas;
    }

    public List<Mesa> getListaMesas() {
        return listaMesas;
    }

    public void setListaMesas(List<Mesa> listaMesas) {
        this.listaMesas = listaMesas;
    }

    public String getFechaActual() {
        return fechaActual;
    }

    public void setFechaActual(String fechaActual) {
        this.fechaActual = fechaActual;
    }

    public List<String> complete(String usuario) {
        List<String> results = new ArrayList<>();
        try {
            Cliente c = new Cliente();
            c.setNombreUsuario(usuario);
            List<Cliente> listaClientes = consultaUniversalFacade.consultar(new Consulta(c));
            for (int i = 0; i < listaClientes.size(); i++) {
                results.add(listaClientes.get(i).getNombreUsuario());
            }
        } catch (Exception ex) {
        }
        return results;
    }

    public String devolverTituloDlg() {
        switch (this.accion) {
            case CREAR:
                return "Crear";
            case EDITAR:
                return "Editar";
            default:
                return "";
        }
    }

    public PermisoPagina consultarPermisos() {
        if (getMi_sesion() != null) {
            return getMi_sesion().consultarPermisos(Reserva.class);
        } else {
            return new PermisoPagina();
        }
    }

    public String devolverTxtBtnCancelarDlg() {
        switch (this.accion) {
            case VER:
                return "Cerrar";
            default:
                return "Cancelar";
        }
    }

    public String devolverTxtLimpiarFormDlg() {
        switch (this.accion) {
            case EDITAR:
                return "Restablecer formulario";
            default:
                return "Limpiar formulario";
        }
    }

    public boolean esCrear() {
        return this.accion == Accion.CREAR;
    }

    public boolean esEditar() {
        return this.accion == Accion.EDITAR;
    }

    public boolean esVer() {
        return this.accion == Accion.VER;
    }

    @PostConstruct
    public void reinicializarChecks() {
        this.checksVisible = new HashMap<>();
        this.checksVisible.put("Id", "codigo");
        this.checksVisible.put("Cantidad de Comensales", "cantComensales");
        this.checksVisible.put("Fecha", "fechaHora");
        this.checksVisible.put("Horario", "horario");
        this.checksVisible.put("Comentarios", "comentario");
        this.selectedChecksVisible = new ArrayList<>();
        this.selectedChecksVisible.add("codigo");
        this.selectedChecksVisible.add("cantComensales");
        this.selectedChecksVisible.add("fechaHora");
        this.selectedChecksVisible.add("horario");
        this.selectedChecksVisible.add("comentario");

        this.setearVisibles();
    }

    public void setearVisibles() {
        if (checksVisible != null && !checksVisible.isEmpty()) {
            for (Map.Entry<String, String> entry : checksVisible.entrySet()) {
                String valor = entry.getValue();
                boolean existe = false;
                if (selectedChecksVisible != null && !selectedChecksVisible.isEmpty()) {
                    for (Iterator<String> it = selectedChecksVisible.iterator(); it.hasNext();) {
                        String colSel = it.next();
                        if (colSel.trim().toLowerCase().equals(valor.trim().toLowerCase())) {
                            existe = true;
                            break;
                        }
                    }
                } else {
                    setearError("Debe seleccionar al menos una columna");
                    break;
                }
                this.colsVisible.put(valor, existe);
            }
        } else {
            setearError("Debe seleccionar al menos una columna");
        }
    }

    public LazyDataModel<Reserva> getListado() {
        if (consultarPermisos().isVer()) {
            return listado;
        } else {
            return null;
        }
    }

    public void setListado(LazyDataModel<Reserva> listado) {
        this.listado = listado;
    }

    public Reserva getTemporal() {
        return temporal;
    }

    public void setTemporal(Reserva temporal) {
        this.temporal = temporal;
    }

    public Map<String, String> getChecksVisible() {
        return checksVisible;
    }

    public void setChecksVisible(Map<String, String> checksVisible) {
        this.checksVisible = checksVisible;
    }

    public List<String> getSelectedChecksVisible() {
        return selectedChecksVisible;
    }

    public void setSelectedChecksVisible(List<String> selectedChecksVisible) {
        this.selectedChecksVisible = selectedChecksVisible;
    }

    public Map<String, Integer> getMesas() {
        return mesas;
    }

    public void setMesas(Map<String, Integer> mesas) {
        this.mesas = mesas;
    }

    public List<Object> getSelectedMesas() {
        return selectedMesas;
    }

    public void setSelectedMesas(List<Object> selectedMesas) {
        this.selectedMesas = selectedMesas;
    }

    public void reinicializarTemporal() {
        this.temporal = new Reserva();
        this.accion = Accion.CREAR;
        this.fecha = new Date();
        this.nombreUsuario = "";
        this.mesasSeleccionadas = new ArrayList<>();
        this.selectedMesas = new ArrayList<>();
        this.mesas = new HashMap<String, Integer>();
        this.cargarHorarios();
    }

    public void establecerTemporal(Reserva objeto, boolean isEditar) {
        this.temporal = (objeto == null) ? new Reserva() : objeto;
        this.accion = (isEditar) ? Accion.EDITAR : Accion.VER;
        this.fecha = this.convertirCalendarADate(this.temporal.getFechaHora());
        this.nomUsuarioCheck = this.temporal.getCliente().getNombreUsuario();
        this.nombreUsuario = this.temporal.getCliente().getNombreUsuario();
        this.mesasSeleccionadas = new ArrayList<>();
        this.cargarMesas();
        this.cargarHorarios();
    }

    public void reinicializarColsVisible() {
        this.colsVisible.clear();
    }

    /**
     *
     * @param col Sin tildes ni espacios y en minúsculas
     * @param visible
     */
    public void establecerColVisible(String col, boolean visible) {
        this.colsVisible.put(col, visible);
    }

    /**
     *
     * @param col Sin tildes ni espacios y en minúsculas
     * @return
     */
    public boolean getColVisible(String col) {
        boolean resp = true;
        if (this.colsVisible.get(col) != null) {
            try {
                resp = (boolean) this.colsVisible.get(col);
            } catch (Exception e) {
            }
        }
        return resp;
    }

    public void eliminar() {
        if (consultarPermisos().isBaja()) {
            if (this.temporal != null) {
                try {
                    entidadFacade.eliminar(this.temporal);
                    this.temporal.setListaMesas(null);
                    entidadFacade.editar(temporal);
                    setearInfo("Operación finalizada correctamente.");
                } catch (Exception e) {
                    setearError(e);
                }
            } else {
                setearInfo("Nada que eliminar.");
            }
        } else {
            setearError("No tiene permisos suficientes para ejecutar esta acción");
        }
    }

    public boolean guardar(String mi_param) {
        switch (this.accion) {
            case CREAR:
                return crear(mi_param);
            case EDITAR:
                return modificar(mi_param);
            default:
                return false;
        }
    }

    private boolean modificar(String mi_param) {
        if (consultarPermisos().isModificacion()) {
            try {
                if (!this.nomUsuarioCheck.equals(this.nombreUsuario)) {
                    Cliente c;
                    Condicional cond = new Condicional("nombreUsuario", this.nombreUsuario, "=");
                    List<Condicional> parametros = new ArrayList<>();
                    parametros.add(cond);
                    List<Cliente> lista = clienteFacade.buscarConParametros(parametros, null, new int[]{0, 1});
                    if (lista != null && lista.size() > 0) {
                        c = lista.get(0);
                        c.setNombreUsuario(this.nombreUsuario);
                        this.temporal.setCliente(c);
                    }
                }
                String codigo = String.valueOf(this.temporal.getId());
                this.temporal.setFechaHora(this.convertirDateACalendar(this.fecha));
                if (!selectedMesas.isEmpty()) {
                    for (int i = 0; i < selectedMesas.size(); i++) {
                        int a = Integer.valueOf((String) selectedMesas.get(i).toString());
                        Mesa m = mesaFacade.buscarPorId(a);
                        this.mesasSeleccionadas.add(m);
                    }
                    this.temporal.setListaMesas(this.mesasSeleccionadas);
                }
                entidadFacade.editar(this.temporal);
                setearInfo("Modificación exitosa " + "de la " + mi_param + " con código: " + codigo);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", true);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                this.cargarHorarios();
                return true;
            } catch (Exception e) {
                setearError(e);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                this.cargarHorarios();
                return false;
            }
        } else {
            return false;
        }
    }

    private boolean crear(String mi_param) {
        if (consultarPermisos().isAlta()) {
            try {
                Cliente c = new Cliente();
                c.setNombreUsuario(this.nombreUsuario);
                c = (Cliente) consultaUniversalFacade.consultarSimpleResult(new Consulta(c));
                this.temporal.setCliente(c);
                this.temporal.setFechaHora(this.convertirDateACalendar(this.fecha));
                if (!selectedMesas.isEmpty()) {
                    for (int i = 0; i < selectedMesas.size(); i++) {
                        int a = Integer.valueOf((String) selectedMesas.get(i).toString());
                        Mesa m = mesaFacade.buscarPorId(a);
                        this.mesasSeleccionadas.add(m);
                    }
                    this.temporal.setListaMesas(this.mesasSeleccionadas);
                }
                entidadFacade.crear(this.temporal);
                setearInfo("Se ha creado " + "exitosamente una nueva " + mi_param);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", true);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                this.cargarHorarios();
                return true;
            } catch (Exception e) {
                setearError(e);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                this.cargarHorarios();
                return false;
            }
        } else {
            return false;
        }
    }

    public enum Accion {

        CREAR, EDITAR, VER;
    }

    public Calendar convertirDateACalendar(Date date) {
        if (date != null) {
            Calendar cal;
            DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
            format.format(date);
            cal = format.getCalendar();
            return cal;
        } else {
            return null;
        }
    }

    public Date convertirCalendarADate(Calendar calendar) {
        if (calendar != null) {
            Date date = calendar.getTime();
            return date;
        } else {
            return null;
        }
    }

    public String reservarCliente(String mi_param) {
        if (consultarPermisos().isAlta()) {
            try {
                this.temporal.setFechaHora(this.convertirDateACalendar(this.fecha));
                this.temporal.setCliente((Cliente) super.getMi_sesion().getUsuario());
                boolean reservada = entidadFacade.reservar(this.temporal);
                if (reservada) {
                    setearInfo("Se ha registrado " + "exitosamente su " + mi_param);
                    RequestContext.getCurrentInstance().addCallbackParam("correcto", true);
                    RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                } else {
                    super.setearAdvertencia("Por favor llame al restaurante para realizar su reserva, "
                            + "en éste momento nos encontramos sin mesas disponibles para la cantidad de comensales solicitados.");
                    RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                    RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                }
            } catch (Exception e) {
                setearError(e);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
            }
        }
        return "tablaAutogestion";
    }

    @PostConstruct
    public void cargarMesas() {
        mesas = new HashMap<String, Integer>();
        this.temporal.setFechaHora(this.convertirDateACalendar(this.fecha));
        this.listaMesas = entidadFacade.mesasParaReservar(this.temporal);
        for (Mesa temp : this.listaMesas) {
            mesas.put("Máximo: " + temp.getMaximo() + " - Mínimo: " + temp.getMinimo(), Integer.valueOf(temp.getId()));
        }
        if (this.esEditar()) {
            List<Mesa> lista = this.temporal.getListaMesas();
            for (Mesa temp : lista) {
                mesas.put("Máximo: " + temp.getMaximo() + " - Mínimo: " + temp.getMinimo(), Integer.valueOf(temp.getId()));
            }
        }
        this.selectedMesas = entidadFacade.mesasSeleccionadas(this.temporal);

    }

    public boolean setVerFecha(Calendar fechaIn, int horario) {
        Calendar calC = Calendar.getInstance();
        int anioC = calC.get(Calendar.YEAR);
        int mesC = calC.get(Calendar.MONTH);
        int diaC = calC.get(Calendar.DAY_OF_MONTH);
        int hora = calC.get(Calendar.HOUR_OF_DAY);
        calC.set(anioC, mesC, diaC, 0, 0, 0);
        int anio = fechaIn.get(Calendar.YEAR);
        int mes = fechaIn.get(Calendar.MONTH);
        int dia = fechaIn.get(Calendar.DAY_OF_MONTH);
        fechaIn.set(anio, mes, dia, 0, 0, 0);
        if (anioC == anio && mes == mesC && dia == diaC) {
            if (horario == 1 && hora > 12) {
                return true;
            }
            if (horario == 2 && hora > 14) {
                return true;
            }
            if (horario == 3 && hora > 19) {
                return true;
            }
            return false;
        } else {
            if (fechaIn.before(calC)) {
                return true;
            } else {
                return false;
            }
        }
    }
}